package com.learn.springboot.service.utils;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author suzheng
 * @date 2024-05-16
 **/
@Slf4j
public class SerialNo {
    private static final String LOCAL_IP_STR ="127.0.0.1";
    private static final InheritableThreadLocal<String> SERIALNO_THREAD_LOCAL = new InheritableThreadLocal<String>();

    public static String getSerialNo(){
        return SERIALNO_THREAD_LOCAL.get();
    }

    public static void setSerialNo(String serialNo){
        SERIALNO_THREAD_LOCAL.set(serialNo);
    }

    public static void init(String appName){
        SERIALNO_THREAD_LOCAL.set(generateSerialNo(appName));
    }

    public static void clear(){
        SERIALNO_THREAD_LOCAL.remove();
    }

    private static Object lock = new Object();
    private static int index = 0;


    private static String localHostAddress = "";
    private static String ipCode = "";


    /**
     * <p>
     * generateSerialNo 流水号生成方法<br/>
     * 生成规则：<br/>
     * 2位 平台编码<br>
     * 12位 IP,如172026007023表示172.26.7.23<br>
     * 15位 时间:yyMMddHHmmssSSS <br>
     * 3位 索引号(000-999) <br>
     * 共32位 如03192168095206150202092529959648
     * </p>
     *
     * @param appName 应用名称
     * @return
     */
    public static String generateSerialNo(String appName) {
        StringBuilder stringBuilder = new StringBuilder(38);
        stringBuilder.append(appName);
        stringBuilder.append(getIpCode());
        stringBuilder.append(DateUtil.newSimpleFormat(DatePattern.PURE_DATETIME_PATTERN));
        String indexV = "000";
        synchronized (lock) {
            index++;
            if (index > 999) {
                index = 0;
            }
            indexV = "" + index;
        }
        if (indexV.length() < 2) {
            indexV = "00" + indexV;
        }else if (indexV.length() < 3) {
            indexV = "0" + indexV;
        }
        stringBuilder.append(indexV);
        return stringBuilder.toString();
    }


    /**
     * 获取Ip地址
     *
     * @return
     */
    public static String getIpCode() {
        String ip = getLocalHostAddress();
        if (ipCode != null && !"".equals(ipCode)) {
            return ipCode;
        }
        String[] ipArray = ip.split("\\.");
        for (int j = 0; j < 4; j++) {
            for (int i = ipArray[j].length(); i < 3; i++) {
                ipCode = ipCode + "0";
            }
            ipCode = ipCode + ipArray[j];
        }
        return ipCode;
    }

    /**
     * <p>
     * 取本机IP地址。
     * </p>
     *
     * @return 本机IP地址 -Djava.net.preferIPv4Stack=TRUE
     * 哈哈，ASIP-NODE加了这个参数，所以取的地址是对的,不会出现取到0:0:0:0:0:0:0:1%1这种IP了
     */
    public static String getLocalHostAddress() {
        if (!localHostAddress.equals("")) {
            return localHostAddress;
        }
        String ip = "";
        String ipBak = "";
        InetAddress inetAddress = null;
        try {
            inetAddress = InetAddress.getLocalHost();
            ip = inetAddress.getHostAddress();
        } catch (Throwable e1) {
            //e1.printStackTrace();
        }
        //log.info(ip + ":" + toStringFromInetAddress(inet));
        if (!"127.0.0.1".equals(ip) || ip.indexOf(':') >= 0) {
            localHostAddress = ip;
            //log.info("java.net.InetAddress.getLocalHost().getHostAddress()="+ ip);
            return ip;
        }
        Enumeration netInterfaces = null;
        try {
            netInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (Throwable e) {
            //e.printStackTrace();
            log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), SerialNo.class.getName(), ExceptionUtil.getMessage(e));
        }
        InetAddress iAddress = null;
        try {
            boolean isTrue = netInterfaces.hasMoreElements();
            while (isTrue) {
                NetworkInterface ni = (NetworkInterface) netInterfaces
                        .nextElement();
                iAddress = (InetAddress) ni.getInetAddresses().nextElement();
                if (!iAddress.isSiteLocalAddress()
                        && !iAddress.isLoopbackAddress()
                        && iAddress.getHostAddress().indexOf(":") == -1) {
                    ip = iAddress.getHostAddress();
                    //log.info(ip + ":" + toStringFromInetAddress(iAddress));
                    //try {
                    //log.info("iAddress.getHostAddress()=" + ip+ ",getLocalHost()=" + iAddress.getLocalHost());
                    //} catch (UnknownHostException e) {
                    //log.info("iAddress.getHostAddress()=" + ip+ ",getLocalHost()=" + e.toString());
                    //e.printStackTrace();
                    //}
                    break;
                } else {
                    ip = iAddress.getHostAddress();
                    //log.info(ip + ":" + toStringFromInetAddress(iAddress));
                    //try {
                    //log.info("NetworkInterface.getNetworkInterfaces().nextElement().getInetAddresses().nextElement().getHostAddress()="+ ip+ ",getLocalHost()="+ iAddress.getLocalHost());
                    //} catch (UnknownHostException e) {
                    //log.info("NetworkInterface.getNetworkInterfaces().nextElement().getInetAddresses().nextElement().getHostAddress()="+ ip + ",getLocalHost()=" + e.toString());
                    //e.printStackTrace();
                    //}
                    if (!"127.0.0.1".equals(ip) && ip.split("\\.").length == 4
                            && ip.indexOf(':') < 0) {
                        ipBak = ip;
                    }
                    ip = "";
                    iAddress = null;
                }
            }
        }catch (Throwable e3) {
            //e3.printStackTrace();
            log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), SerialNo.class.getName(), ExceptionUtil.getMessage(e3));
        }
        if (!LOCAL_IP_STR.equals(ip) && ip.split("\\.").length == 4
                && ip.indexOf(':') < 0) {
            localHostAddress = ip;
            return ip;
        }
        try {
            Enumeration<?> e1 = (Enumeration<?>) NetworkInterface
                    .getNetworkInterfaces();
            while (e1.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) e1.nextElement();
                if (!"eth0".equals(ni.getName())
                        && !"eth1".equals(ni.getName())
                        && !"bond0".equals(ni.getName())) {
                    //log.info("NetworkInterface.getNetworkInterfaces().nextElement().getName()="+ ni.getName());
                    continue;
                } else {
                    Enumeration<?> e2 = ni.getInetAddresses();
                    while (e2.hasMoreElements()) {
                        InetAddress ia = (InetAddress) e2.nextElement();
                        if (ia instanceof Inet6Address) {
                            continue;
                        }
                        ip = ia.getHostAddress();
                        //log.info(ip + ":" + toStringFromInetAddress(ia));
                        //try {
                        //log.info("NetworkInterface.getNetworkInterfaces():"+ ni.getName()+ ".getInetAddresses().nextElement().getHostAddress()="+ ip + ",getLocalHost()="+ ia.getLocalHost());
                        //} catch (UnknownHostException e) {
                        //log.info("NetworkInterface.getNetworkInterfaces():"+ ni.getName()+ ".getInetAddresses().nextElement().getHostAddress()="+ ip + ",getLocalHost()=" + e.toString());
                        //e.printStackTrace();
                        //}
                        if (!ia.isSiteLocalAddress() && !LOCAL_IP_STR.equals(ip)
                                && ip.split("\\.").length == 4
                                && ip.indexOf(':') < 0) {
                            localHostAddress = ip;
                            return ip;
                        }

                        if ("eth1".equals(ni.getName())
                                && !ia.isSiteLocalAddress()
                                && !LOCAL_IP_STR.equals(ip)
                                && ip.split("\\.").length == 4
                                && ip.indexOf(':') < 0) {
                            ipBak = ip;
                            ip = "";
                        }

                    }
                    break;
                }
            }
        } catch (Throwable e) {
            //e.printStackTrace();
        }
        if (!LOCAL_IP_STR.equals(ip) && ip.split("\\.").length == 4
                && ip.indexOf(':') < 0) {
            localHostAddress = ip;
            return ip;
        }
        if (ipBak.split("\\.").length == 4 && ipBak.indexOf(':') < 0) {
            localHostAddress = ipBak;
            return ipBak;
        }
        localHostAddress = ip;
        return ip;
    }
}
